package com.cyy.learn.jsonConvert

import cn.hutool.core.util.XmlUtil
import cn.hutool.json.JSONArray
import cn.hutool.json.JSONObject
import cn.hutool.json.JSONUtil
import com.alibaba.fastjson.JSON
import com.cyy.app.Styles.Companion.jsonConvertBtn
import com.cyy.util.*
import com.cyy.util.ArrayProcessor
import javafx.beans.property.SimpleStringProperty
import javafx.geometry.Pos
import javafx.scene.layout.Priority
import tornadofx.*
import org.apache.commons.betwixt.schema.Element
import org.apache.commons.lang3.StringUtils
import org.yaml.snakeyaml.Yaml
import java.io.StringReader
import java.math.BigDecimal
import java.util.*
import java.util.TreeSet
import java.util.Enumeration
import org.nd4j.nativeblas.Nd4jCpu.add
import org.nd4j.nativeblas.Nd4jCpu.split

val strIn = SimpleStringProperty("")
val strOut = SimpleStringProperty("")

class JsonConvert : View("JsonConvert") {
    val C: JsonConvertController by inject()

    override val root = anchorpane() {
        splitpane() {
            textarea(strIn)
            hbox(5) {
                vbox(5) {
                    addClass(jsonConvertBtn)
                    button("Json转xml") {
                        action {
                            C.jsonToXmlAction()
                        }
                    }
                    button("xml转Json") {
                        action {
                            C.xmlToJsonAction()
                        }
                    }
                    button("转javaBean") {
                        action {
                            C.jsonToJavaBeanAction()
                        }
                    }
                    button("转C# bean") {
                        action {
                            C.jsonToCAction()
                        }
                    }
                    button("Excel转Json") {
                        action {
                            C.excelToJsonAction()
                        }
                    }
                    button("Json转Excel") {
                        action {
                            C.jsonToExcelAction()
                        }
                    }
                    button("Json转Yaml") {
                        action {
                            C.jsonToYamlAction()
                        }
                    }
                    button("Yaml转Json") {
                        action {
                            C.yamlToJsonAction()
                        }
                    }
                    button("Props转Yaml") {
                        action {
                            C.propsToYamlAction()
                        }
                    }
                    button("Yaml转Props") {
                        action {
                            C.yamlToPropsAction()
                        }
                    }
                }
                textarea(strOut) {
                    hgrow = Priority.ALWAYS
                }
                alignment = Pos.CENTER
            }
        }
        paddingAll = 10.0
    }
}

class JsonConvertController : Controller() {
    fun jsonToXmlAction() {
        try {
            strOut.value = JSONUtil.toXmlStr(JSONUtil.parse(strIn.value))
            strOut.value = XmlUtil.format(strOut.value)
        } catch (e: Exception) {
//            log.error("转换错误：", e)
            TooltipUtil.showToast("转换错误" + e.message)
        }
    }

    fun xmlToJsonAction() {
        strOut.value = JSONUtil.toJsonPrettyStr(JSONUtil.xmlToJson(strIn.value))
    }

    fun jsonToJavaBeanAction() {
        val jsonObj = JSONUtil.parse(strIn.value)
        strOut.value = jsonToJavaBean("XRootBean", jsonObj)
    }

    private fun jsonToJavaBean(beanName: String, jsonObject: Any): String {
        var jsonObject = jsonObject
        if (jsonObject is List<*>) {
            jsonObject = jsonObject[0]!!
        }
        val afterString = StringBuilder()
        val importString = StringBuilder("package ;")
        val propertyString = StringBuilder()
        val getSetString = StringBuilder()
        val subclass = HashMap<String, String>()
        for (entry in (jsonObject as JSONObject).entries) {
            val value = entry.value
            val key = entry.key
            val keyName = StrUtil.fristToUpCase(key)
            if (value is String) {
                propertyString.append("\n\tprivate String $key;")
                getSetString.append("\n\tpublic void set$keyName(String $key){\n\t\tthis.$key = $key;\n\t}")
                getSetString.append("\n\tpublic String get$keyName(){\n\t\treturn this.$key;\n\t}")
            } else if (value is Int) {
                propertyString.append("\n\tprivate int $key;")
                getSetString.append("\n\tpublic void set$keyName(int $key){\n\t\tthis.$key = $key;\n\t}")
                getSetString.append("\n\tpublic int get$keyName(){\n\t\treturn this.$key;\n\t}")
            } else if (value is BigDecimal) {
                propertyString.append("\n\tprivate double $key;")
                getSetString.append("\n\tpublic void set$keyName(double $key){\n\t\tthis.$key = $key;\n\t}")
                getSetString.append("\n\tpublic double get$keyName(){\n\t\treturn this.$key;\n\t}")
            } else if (value is List<*>) {
                propertyString.append("\n\tprivate List<$keyName> $key;")
                importString.append("\nimport java.util.List;")
                getSetString.append("\n\tpublic void set$keyName(List<$keyName> $key){\n\t\tthis.$key = $key;\n\t}")
                getSetString.append("\n\tpublic List<$keyName> get$keyName(){\n\t\treturn this.$key;\n\t}")
                val subclassString = keyName?.let { jsonToJavaBean(it, value) }
                subclass[keyName!!] = subclassString!!
            } else if (value is Map<*, *>) {
                propertyString.append("\n\tprivate $keyName $key;")
                val subclassString = keyName?.let { jsonToJavaBean(it, value) }
                subclass[keyName!!] = subclassString!!
                getSetString.append("\n\tpublic void set$keyName($keyName $key){\n\t\tthis.$key = $key;\n\t}")
                getSetString.append("\n\tpublic $keyName get$keyName(){\n\t\treturn this.$key;\n\t}")
            }
        }
        afterString.append(importString.toString())
        afterString.append("\npublic class $beanName\n{")
        afterString.append(propertyString.toString())
        afterString.append("\n" + getSetString.toString())
        afterString.append("\n}")
        subclass.forEach { (key, value) ->
            afterString.append("\n\n=============================\n")
            afterString.append(value)
        }
        return afterString.toString()
    }

    fun jsonToCAction() {
        val jsonObj = JSONUtil.parse(strIn.value)
        strOut.value = jsonToCBean("XRootBean", jsonObj)
    }

    private fun jsonToCBean(beanName: String, jsonObject: Any): String {
        var jsonObject = jsonObject
        if (jsonObject is List<*>) {
            jsonObject = jsonObject[0]!!
        }
        val afterString = StringBuilder()
        val propertyString = StringBuilder()
        val subclass = HashMap<String, String>()
        for ((key, value) in jsonObject as JSONObject) {
            val keyName = StrUtil.fristToUpCase(key)
            if (value is String) {
                propertyString.append("\n\tpublic string $key {get; set;}")
            } else if (value is Int) {
                propertyString.append("\n\tpublic int $key {get; set;}")
            } else if (value is BigDecimal) {
                propertyString.append("\n\tpublic double $key {get; set;}")
            } else if (value is List<*>) {
                propertyString.append("\n\tpublic List<$keyName> $key {get; set;}")
                val subclassString = keyName?.let { jsonToCBean(it, value) }
                subclass[keyName!!] = subclassString!!
            } else if (value is Map<*, *>) {
                propertyString.append("\n\tpublic $keyName $key {get; set;}")
                val subclassString = keyName?.let { jsonToCBean(it, value) }
                subclass[keyName!!] = subclassString!!
            }
        }
        afterString.append("\npublic class $beanName\n{")
        afterString.append(propertyString.toString())
        afterString.append("\n}")
        subclass.forEach { (key, value) ->
            afterString.append("\n\n=============================\n")
            afterString.append(value)
        }
        return afterString.toString()
    }

    fun excelToJsonAction() {
        val afterStringStr = strIn.value.split("\n")
        val header = afterStringStr[0].split("\t".toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()
        val jsonArray = JSONArray()
        for (i in 1 until afterStringStr.size) {
            val objectStr = afterStringStr[i].split("\t".toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()
            val jsonObject = JSONObject()
            for (j in header.indices) {
                jsonObject[header[j]] = objectStr[j]
            }
            jsonArray.add(jsonObject)
        }
        strOut.value = JSON.toJSONString(jsonArray, true)
    }

    fun jsonToExcelAction() {
        val jsonArray =JSONUtil.parseArray(strIn.value)
        val stringBuilder = StringBuilder()
        stringBuilder.append(StringUtils.join(jsonArray.getJSONObject(0).keys, "\t"))
        for (jsonObject in jsonArray.toArray(arrayOfNulls<JSONObject>(0))) {
            stringBuilder.append("\n" + StringUtils.join(jsonObject?.values, "\t"))
        }
    }

    fun jsonToYamlAction() {
        val jsonObj = JSONUtil.parse(strIn.value)
        strOut.value = Yaml().dump(jsonObj)
    }

    fun yamlToJsonAction() {
        strOut.value = JSONUtil.toJsonPrettyStr(Yaml().load(strIn.value))
    }

    fun propsToYamlAction() {
        val properties = Properties()
        properties.load(StringReader(strIn.value))
        val tree = TreeBuilder(properties, true).build()
        strOut.value = ArrayProcessor(tree).apply().toYAML()
    }

    fun yamlToPropsAction() {
        if(strIn.value.isNullOrEmpty()){

        val yaml = Yaml()
        val map = yaml.load(strIn.value) as Map<String, Any>
        val properties = object : Properties() {
//            @Synchronized
//            override fun keys(): Enumeration<Any> {
//                return Collections.enumeration(TreeSet(super.keys()))
//            }
        }
        iterateAndProcess(properties, map, "")
        val stringBuffer = StringBuffer()
        val iterator = properties.keys.iterator()
        while (iterator.hasNext()) {
            val key = iterator.next()
            stringBuffer.append("${key}=${properties[key]}\n")
        }
        strOut.value =stringBuffer.toString()
        }
    }

    private fun iterateAndProcess(properties: Properties, ymlEntry: Map<String, Any>, rootKey: String) {
        for (key in ymlEntry.keys) {
            val value = ymlEntry[key]
            if (value is Map<*, *>) {
                iterateAndProcess(properties, value as Map<String, Any>, if (StringUtils.isEmpty(rootKey))
                    key
                else
                    rootKey
                            + "." + key)
            } else {
                properties.setProperty(if (StringUtils.isEmpty(rootKey)) key else "$rootKey.$key", value.toString())
            }
        }
    }
}